#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/platform_device.h> 
#include <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/i2c.h>

#define MPU6050_NAME  			"mpu6050"
#define MPU6050_NUM	 			1

#define	MPU6050_SMPLRT_DIV		0x19	//陀螺仪采样率，典型值：0x07(125Hz)
#define	MPU6050_CONFIG			0x1A	//低通滤波频率，典型值：0x06(5Hz)
#define	MPU6050_GYRO_CONFIG		0x1B	//陀螺仪自检及测量范围，典型值：0x18(不自检，2000deg/s)
#define	MPU6050_ACCEL_CONFIG	0x1C	//加速计自检、测量范围及高通滤波频率，典型值：0x01(不自检，2G，5Hz)
#define	MPU6050_PWR_MGMT_1		0x6B	//电源管理，典型值：0x00(正常启用)
#define MPU6050_DATA_ADDR		0x3B    //MSB数据地址共14字节ACCEL_X、ACCEL_Y、ACCEL_Z、TEMP、GYRO_X、GYRO_Y、GYRO_Z每个两字节

struct mpu6050_st
{
	dev_t devID;
	int major;
	int minor;
	struct cdev cdev;
	struct class *class;
	struct device *device;
	struct device_node *node;
	struct i2c_client *client;
};
static struct mpu6050_st mpu6050;

static int mpu6050_read_regs(struct mpu6050_st *dev, u8 reg, void *buf, int lenth)
{
	int ret;
	struct i2c_msg msg[2];
	struct i2c_client *client = dev->client;

	//写寄存器地址
	msg[0].addr 	= client->addr;
	msg[0].flags 	= 0;
	msg[0].buf 		= &reg;
	msg[0].len 		= 1;

	//读数据
	msg[1].addr 	= client->addr;
	msg[1].flags 	= I2C_M_RD;
	msg[1].buf 		= buf;
	msg[1].len 		= lenth;

	ret = i2c_transfer(client->adapter , msg, 2);
	if(ret ==2)
	{
		ret =0;
	}
	else
	{
		printk("mpu6050_read_regs error\r\n");
		return -EINVAL;
	}

	return 0;
}

static int mpu6050_write_regs(struct mpu6050_st *dev, u8 reg, void *buf, int lenth)
{
	int ret;
	u8 sendBuff[256] ={0};
	struct i2c_msg msg;
	struct i2c_client *client = dev->client;

	sendBuff[0] = reg;
	memcpy(&sendBuff[1],buf,lenth);

	//写数据
	msg.addr 	= client->addr;
	msg.flags 	= 0;
	msg.buf 	= sendBuff;
	msg.len 	= lenth+1;

	ret = i2c_transfer(client->adapter, &msg, 1);
	if(ret ==1)
	{
		ret =0;
	}
	else
	{
		printk("mpu6050_write_regs error\r\n");
		return -EINVAL;
	}

	return 0;
}

static u8 mpu6050_read_reg(struct mpu6050_st *dev, u8 reg)
{
	u8 data;
	mpu6050_read_regs(dev, reg, &data, 1);

	return data;
}

static void mpu6050_write_reg(struct mpu6050_st *dev, u8 reg, u8 data)
{
	mpu6050_write_regs(dev, reg, &data, 1);
}

static void InitMPU6050(struct mpu6050_st *dev)
{
	mpu6050_write_reg(dev, MPU6050_PWR_MGMT_1, 0x00);	//解除休眠状态
	mpu6050_write_reg(dev, MPU6050_SMPLRT_DIV, 0x07);
	mpu6050_write_reg(dev, MPU6050_CONFIG, 0x06);
	mpu6050_write_reg(dev, MPU6050_GYRO_CONFIG, 0x18);
	mpu6050_write_reg(dev, MPU6050_ACCEL_CONFIG, 0x01);
}

static ssize_t mpu6050_read(struct file *flip, char __user *buff, size_t cnt, loff_t *off)
{
	int ret=0;
	u8 dataBuff[14] = {0};
	struct mpu6050_st *me = flip->private_data;

	ret = mpu6050_read_regs(me, MPU6050_DATA_ADDR, dataBuff, 14);
	if(ret<0)
	{
		printk("mpu6050_read error\r\n");
		return -EINVAL;
	}
	
	ret = copy_to_user(buff, dataBuff, 14);
	if(ret)
	{
		printk("copy_to_user error\r\n");
		return -EINVAL;
	}

	return 0;
}

static int mpu6050_open(struct inode *inode, struct file *flip)
{
	flip->private_data = &mpu6050;
	InitMPU6050(&mpu6050);
	
	return 0;
}

static int mpu6050_release(struct inode *inode, struct file *flip)
{
	return 0;
}

static const struct file_operations mpu6050_fops = 
{
	.owner 		= THIS_MODULE,
	.read 		= mpu6050_read,
	.open 		= mpu6050_open,
	.release 	= mpu6050_release,
};

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *dev)
{
	int ret =0;

	//申请设备号
	if(mpu6050.major)
	{
		mpu6050.devID = MKDEV(mpu6050.major, 0);
		ret = register_chrdev_region(mpu6050.devID, MPU6050_NUM, MPU6050_NAME);
		if(ret <0)
		{
			printk("register_chrdev_region error\r\n");
			goto chrdev_err;
		}
	}
	else
	{
		ret = alloc_chrdev_region(&mpu6050.devID, 0, MPU6050_NUM, MPU6050_NAME);
		if(ret <0)
		{
			printk("alloc_chrdev_region error\r\n");
			goto chrdev_err;
		}
		mpu6050.major = MAJOR(mpu6050.devID);
		mpu6050.minor = MINOR(mpu6050.devID);
	}

	//创建字符设备
	mpu6050.cdev.owner = THIS_MODULE;
	cdev_init(&mpu6050.cdev, &mpu6050_fops);
	ret = cdev_add(&mpu6050.cdev, mpu6050.devID, MPU6050_NUM);
	if(ret <0)
	{
		printk("cdev_add error\r\n");
		goto cdev_err;
	}

	//创建类
	mpu6050.class = class_create(THIS_MODULE, MPU6050_NAME);
	if(IS_ERR(mpu6050.class))
	{
		printk("class_create error\r\n");
		ret = PTR_ERR(mpu6050.class);
		goto class_err;
	}

	//常见设备
	mpu6050.device = device_create(mpu6050.class, NULL, mpu6050.devID, NULL, MPU6050_NAME);
	if(IS_ERR(mpu6050.device))
	{
		printk("device_create error\r\n");
		ret = PTR_ERR(mpu6050.device);
		goto device_err;
	}
	
	mpu6050.client = client;
	printk("mpu6050_probe sucess\r\n");
	
	return 0;

device_err:
	class_destroy(mpu6050.class);
class_err:
	cdev_del(&mpu6050.cdev);
cdev_err:
	unregister_chrdev_region(mpu6050.devID, MPU6050_NUM);
chrdev_err:
	return ret;
}

static int mpu6050_remove(struct i2c_client *client)
{
	//卸载字符设备
	cdev_del(&mpu6050.cdev);
	unregister_chrdev_region(mpu6050.devID, MPU6050_NUM);

	//删除设备、类
	device_destroy(mpu6050.class, mpu6050.devID);
	class_destroy(mpu6050.class);

	printk("mpu6050_remove sucess\r\n");
	return 0;
}

static const struct i2c_device_id  mpu6050_id[]=
{
	{"mpu6050",0},
	{}
};

static const struct of_device_id mpu6050_of_match[] =
{
	{.compatible = "mpu6050"},
	{}
};

static struct i2c_driver mpu6050_dev = 
{
	.probe 	= mpu6050_probe,
	.remove = mpu6050_remove,
	.driver = {
		.owner 	= THIS_MODULE,
		.name 	= "mpu6050",
		.of_match_table = mpu6050_of_match,
	},
	.id_table = mpu6050_id,
};

static int __init mpu6050_init(void)
{
	return i2c_add_driver(&mpu6050_dev);
}

static void __exit mpu6050_exit(void)
{
	i2c_del_driver(&mpu6050_dev);
}

module_init(mpu6050_init);
module_exit(mpu6050_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jtb");

